package com.hooper.iot.face.handler;


import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.hooper.iot.constants.MsgTypeConstants;
import com.hooper.iot.entity.CommonResponse;
import com.hooper.iot.entity.DelFaceEntity;
import com.hooper.iot.entity.FaceRspDto;
import com.hooper.iot.entity.addFace.AddFaceReq;
import com.hooper.iot.entity.lPersonnelCode;
import com.hooper.iot.face.components.ChannelRepository;
import com.hooper.iot.face.components.DeviceInfoRespository;
import com.hooper.iot.face.queue.ConsumerQueueReposity;
import com.hooper.iot.util.IdUntil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicInteger;

import static io.netty.handler.codec.http.HttpUtil.isKeepAlive;
import static io.netty.handler.codec.http.HttpUtil.setContentLength;


/**
 * 其他业务拓展模板参考
 */
@Component(value = "faceServerHandler")
@ChannelHandler.Sharable
@Slf4j
public class FaceServerHandler extends ChannelInboundHandlerAdapter {
    @Resource(name = "channelRepository")
    private ChannelRepository channelRepository;
    @Resource(name = "poolExecutor")
    private ExecutorService poolExecutor;
    @Autowired
    private KafkaTemplate kafkaTemplate;
    @Autowired
    DeviceInfoRespository deviceInfoRespository;
    @Autowired
    private ConsumerQueueReposity consumerQueueReposity;

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        if (msg instanceof FullHttpRequest) {

            handleHttpRequest(ctx, (FullHttpRequest) msg);

        } else if (msg instanceof TextWebSocketFrame) {
            handleSocketRequest(ctx,(TextWebSocketFrame)msg);
        }
        ctx.writeAndFlush("next");
        //交给下个处理器处理
        ctx.fireChannelRead(msg);
    }

    private void handleSocketRequest(ChannelHandlerContext ctx, TextWebSocketFrame msg) {
        //TODO 有些消息类型不该处理，也不该转换为TextWebSocketFrame格式
        JSONObject result = JSONObject.parseObject(msg.text());
        if (result!=null&&result.getString("msgType").equals("SERVER_REQUEST")&&result.getJSONObject("body")!=null&&result.getJSONObject("body").containsKey("callType")){
            JSONObject object = deviceInfoRespository.get(ctx.channel().remoteAddress().toString().substring(1, ctx.channel().remoteAddress().toString().indexOf(":")));

            poolExecutor.execute(()->{
                if (object!=null&&object.getString("id")!=null&&consumerQueueReposity.get(object.getString("id"))!=null){
                    AtomicInteger integer = consumerQueueReposity.get(object.getString("id"));
                    synchronized (integer){
                        int count = consumerQueueReposity.get(object.getString("id")).decrementAndGet();
                        log.info("设备"+object.getString("id")+"负载减1，为："+count);
                    }
                }else {
                    log.info("");
                }
                JSONObject callback  = result;
                lPersonnelCode code = new lPersonnelCode();
                code.setUptKey(callback.getString("msgId"));
                log.info("下发callback=====>"+code.getUptKey());
                Map<String,JSONObject> map = deviceInfoRespository.getMap();
                code.setDoorId(map.get(callback.getString("deviceId")).getString("id"));
                code.setHandleDesc("");
                //TODO 当消息类型为删除人脸时，此处无法取值，但不影响流程 可以在此处进行业务控制，猜测业务端是根据msgid做的判断，其他的都是冗余信息
                try {
                    code.setUserId(callback.getJSONObject("body").getJSONArray("persons").getObject(0,JSONObject.class).getString("personId"));
                }catch (NullPointerException exception){
                    log.info("未获取到人员id");
                }
                FaceRspDto faceRspDto = new FaceRspDto();
                faceRspDto.setLPersonnelCode(Arrays.asList(code));
                log.info("==========回应业务端消息为"+JSONObject.toJSONString(faceRspDto));
                kafkaTemplate.send("usmp_sycfacedoor_usr_msg",UUID.randomUUID().toString(),JSONObject.toJSONString(faceRspDto));
            });
        }else if (result!=null&&result.getString("msgType").equals("DATA_COLLECTION_TO_SERVER")){
            poolExecutor.execute(()->{
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("accessId",result.getString("deviceId"));
                jsonObject.put("accessName",result.getString(deviceInfoRespository.get(result.getString("deviceId")).getString("name"))==null?result.getString(deviceInfoRespository.get(result.getString("deviceId")).getString("name")):"未知设备");
                jsonObject.put("accessrecordId", UUID.randomUUID().toString());
                jsonObject.put("acquisitionTime",simpleDateFormat.format(new Date(Long.valueOf(result.getString("msgDateStamp")))));
                jsonObject.put("birthdate",result.getJSONObject("body").getString("birthdate"));
                jsonObject.put("businessCode","entrance");
                jsonObject.put("cardHeadId","");
                jsonObject.put("cardHeadUrl","");
                jsonObject.put("cardList",result.getJSONObject("body").getJSONArray("accessCards"));
                jsonObject.put("deviceCode",deviceInfoRespository.get(jsonObject.getString("accessId")).getString("id"));
                jsonObject.put("enaexCodes",Arrays.asList(2));
                jsonObject.put("ethnicGroup",result.getJSONObject("body").getString("ethnicGroup"));
                jsonObject.put("facialFeatureList",result.getJSONObject("body").getJSONArray("facialFeature"));
                jsonObject.put("fingerprintList",result.getJSONObject("body").getJSONArray("fingerprint"));
                jsonObject.put("headPortrait",result.getJSONObject("body").getJSONArray("images").getJSONObject(0).getString("data")+".jpg");
//                jsonObject.put("identityList",result.getJSONObject("body").getJSONArray("fingerprint"));
                JSONObject identityList = new JSONObject();
                identityList.put("expandInfo","");
                identityList.put("identityNo",result.getJSONObject("body").getString("identityNo"));
                identityList.put("identityType",this.getIdentityType(result.getJSONObject("body").getString("identityType")));
                jsonObject.put("identityList",Arrays.asList(identityList));
                jsonObject.put("isMatch",result.getJSONObject("body").getInteger("isMatch")==0?true:false);
                jsonObject.put("nationality",result.getJSONObject("body").getString("nationaliy"));
                jsonObject.put("permanentAddress",result.getJSONObject("body").getString("permanentAddress"));
                jsonObject.put("permanentCode",result.getJSONObject("body").getString("permanentCode"));
                jsonObject.put("permanentRegion",result.getJSONObject("body").getString("permanentRegion"));
                jsonObject.put("personExpiryDate",simpleDateFormat.format(new Date(Long.valueOf(result.getJSONObject("body").getLong("personExpiryDate")))));
                jsonObject.put("sex",result.getJSONObject("body").getInteger("sex"));
                jsonObject.put("souceId",result.getJSONObject("body").getJSONArray("images").getJSONObject(0).getString("data"));
                jsonObject.put("userName",result.getJSONObject("body").getString("name"));
                log.info("人员登记======>"+jsonObject.toJSONString());
                kafkaTemplate.send("usmp_addfacedoor_usr_msg",UUID.randomUUID().toString(),jsonObject.toJSONString());
            });
        }

    }
    private Integer getIdentityType(String identityType){
        if (identityType.equals("IDCARD")  ){
            return  1;
        }else if (identityType.equals("SOCIALCARD")){
            return 2;
        }else if (identityType.equals("PASSPORT")){
            return 3;
        }else if (identityType.equals("EMPLOYEE")){
            return 4;
        }else{
            return 5;
        }
    }

    private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) {
        // 如果 HTTP 解码失败, 返回HTTP异常
        if (!req.getDecoderResult().isSuccess() || (!"websocket".equalsIgnoreCase(req.headers().get("Upgrade")))) {
            //TODO 增加其他方式调用http实现控制人脸下发,由下个控制器去处理
            sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK));
            return;
        }
    }

    private void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest req, FullHttpResponse res) {
        if (res.getStatus().code() == MsgTypeConstants.HTTP_STATUS_200) {
            System.out.println(req.headers().get(MsgTypeConstants.REMOTE_HOST));
            if (req.headers().contains(MsgTypeConstants.MSG_TYPE) && req.headers().contains(MsgTypeConstants.REMOTE_HOST)) {
                JSONObject requestBody = JSONObject.parseObject(req.content().toString(CharsetUtil.UTF_8));

                Channel channel = channelRepository.get(req.headers().get(MsgTypeConstants.REMOTE_HOST));

                if (req.headers().get(MsgTypeConstants.MSG_TYPE).equals(MsgTypeConstants.SEND_ADD_FACE_ID)) {
                    AddFaceReq addFaceReq = new AddFaceReq();
                    AddFaceReq.Body body = addFaceReq.new Body();
                    AddFaceReq.Images images = addFaceReq.new Images();
                    //Image
                    images.setData(requestBody.getString("imageUri"));
                    images.setImageType("FACE");
                    images.setFileFormat("URI");
                    //Body
                    body.setAccessCards(requestBody.getString("accessCards"));
                    body.setControltype(requestBody.getString("controltype"));
                    body.setFacialFeature(requestBody.getString("facialFeature"));
                    body.setFingerprint(requestBody.getString("facialFeature"));
                    body.setIdentityNo(requestBody.getString("identityNo"));
                    body.setIdentityType(requestBody.getString("identityType"));
                    body.setImages(Arrays.asList(images));
                    body.setMatchType(requestBody.getString("matchType"));
                    body.setName(requestBody.getString("name"));
                    body.setPersonAuthType(requestBody.getString("personAuthType"));
                    body.setPersonExpiryDate(requestBody.getLong("personExpiryDate"));
                    body.setPersonId(requestBody.getString("personId"));
                    body.setPersonType(requestBody.getString("personType"));
                    body.setSex(requestBody.getInteger("sex"));
                    //主体根
                    addFaceReq.setCallBack(true);
                    addFaceReq.setDeviceId(requestBody.getString("deviceId"));
                    addFaceReq.setMsgId(IdUntil.getMessgeId());
                    addFaceReq.setMsgType(MsgTypeConstants.SEND_ADD_FACE_ID);
                    addFaceReq.setBody(Arrays.asList(body));
                    SerializerFeature[] arg = new SerializerFeature[]{SerializerFeature.WriteMapNullValue, SerializerFeature.QuoteFieldNames};
                    try {
                        channel.write(new TextWebSocketFrame(JSONObject.toJSONString(addFaceReq, arg)));
                        channel.flush();
                        ByteBuf buf = Unpooled.copiedBuffer(JSONObject.toJSONString(CommonResponse.success("下发成功！")), CharsetUtil.UTF_8);
                        res.content().writeBytes(buf);
                        buf.release();
                        setContentLength(res, res.content().readableBytes());
                    } catch (Exception e) {
                        log.info("下发失败====》" + e.toString());
                        ByteBuf buf = Unpooled.copiedBuffer(JSONObject.toJSONString(CommonResponse.failed("下发失败，设备不在线！")), CharsetUtil.UTF_8);
                        res.content().writeBytes(buf);
                        buf.release();
                        setContentLength(res, res.content().readableBytes());
                    }
                } else if (req.headers().get(MsgTypeConstants.MSG_TYPE).equals(MsgTypeConstants.DEL_FACE_ID)) {
                    //删除人脸
                    DelFaceEntity delFaceEntity = new DelFaceEntity();
                    DelFaceEntity.Body body = delFaceEntity.new Body();
                    delFaceEntity.setMsgDate(System.currentTimeMillis());
                    delFaceEntity.setDeviceId(requestBody.getString("deviceId"));
                    delFaceEntity.setCallBack(true);
                    delFaceEntity.setMsgId(IdUntil.getMessgeId());
                    delFaceEntity.setMsgType(MsgTypeConstants.DEL_FACE_ID);
                    //body
                    body.setIdentityNo(requestBody.getString("identityNo"));
                    body.setPersonId(requestBody.getString("personId"));
                    delFaceEntity.setBody(Arrays.asList(body));
                    SerializerFeature[] arg = new SerializerFeature[]{SerializerFeature.WriteMapNullValue, SerializerFeature.QuoteFieldNames};
                    try {
                        channel.write(new TextWebSocketFrame(JSONObject.toJSONString(delFaceEntity, arg)));
                        channel.flush();
                        ByteBuf buf = Unpooled.copiedBuffer(JSONObject.toJSONString(CommonResponse.success("删除人脸成功！")), CharsetUtil.UTF_8);
                        res.content().writeBytes(buf);
                        buf.release();
                        setContentLength(res, res.content().readableBytes());
                    } catch (Exception e) {
                        log.info("下发失败====》" + e.toString());
                        ByteBuf buf = Unpooled.copiedBuffer(JSONObject.toJSONString(CommonResponse.failed("下发失败，设备不在线！")), CharsetUtil.UTF_8);
                        res.content().writeBytes(buf);
                        buf.release();
                        setContentLength(res, res.content().readableBytes());
                    }
                } else if (req.headers().get(MsgTypeConstants.MSG_TYPE).equals("test")) {
                    //删除人脸
                    String content = req.content().toString(Charset.forName("UTF-8"));
                    try {
                        channel.write(new TextWebSocketFrame(content));
                        channel.flush();
                        ByteBuf buf = Unpooled.copiedBuffer(JSONObject.toJSONString(CommonResponse.success("消息已发送！")), CharsetUtil.UTF_8);
                        res.content().writeBytes(buf);
                        buf.release();
                        setContentLength(res, res.content().readableBytes());
                    } catch (Exception e) {
                        log.info("下发失败====》" + e.toString());
                        ByteBuf buf = Unpooled.copiedBuffer(JSONObject.toJSONString(CommonResponse.failed("下发失败，设备不在线！")), CharsetUtil.UTF_8);
                        res.content().writeBytes(buf);
                        buf.release();
                        setContentLength(res, res.content().readableBytes());
                    }
                } else {
                    return;
                }

            } else {
                ByteBuf buf = Unpooled.copiedBuffer(JSONObject.toJSONString(CommonResponse.failed("参数不符！")), CharsetUtil.UTF_8);
                res.content().writeBytes(buf);
                buf.release();
                setContentLength(res, res.content().readableBytes());
            }

        }
        // 如果是非 Keep-Alive, 关闭连接
        ChannelFuture f = ctx.channel().writeAndFlush(res);
        if (!isKeepAlive(req) || res.getStatus().code() != 200) {
            f.addListener(ChannelFutureListener.CLOSE);
        }
    }


}
